package org.study.redis.boot.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
import org.springframework.data.redis.serializer.JacksonJsonRedisSerializer;
import org.study.redis.boot.component.RedisReceiver;
import org.study.redis.boot.enums.RedisConstant;
import tools.jackson.databind.DefaultTyping;
import tools.jackson.databind.introspect.VisibilityChecker;
import tools.jackson.databind.json.JsonMapper;
import tools.jackson.databind.jsontype.BasicPolymorphicTypeValidator;

/**
 * 类的描述
 *
 * @author Administrator
 * @date 2021-06-21
 */
@Configuration
public class RedisMessageListener {
    /**
     * Redis 消息监听器容器
     *
     * @param lettuceConnectionFactory
     * @param collectListenerAdapter   收藏消息订阅处理器
     * @param commentListenerAdapter   评论消息订阅处理器
     * @param focusListenerAdapter     关注消息订阅处理器
     * @param praiseListenerAdapter    点赞消息订阅处理器
     * @return
     */
    @Bean
    RedisMessageListenerContainer container(RedisConnectionFactory lettuceConnectionFactory,
                                            MessageListenerAdapter collectListenerAdapter,
                                            MessageListenerAdapter commentListenerAdapter,
                                            MessageListenerAdapter focusListenerAdapter,
                                            MessageListenerAdapter praiseListenerAdapter,
                                            MessageListenerAdapter webSocketTopicListenerAdapter) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(lettuceConnectionFactory);
        // 以下为修改默认的序列化方式，网上大多数消息发布订阅都是String类型，但是实际中数据类型肯定不止String类型
        /*ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL);*/
        JsonMapper jsonMapper = JsonMapper.builder()
                // 开启"默认类型信息"，仅作用于非 final 类
                .activateDefaultTyping(BasicPolymorphicTypeValidator.builder()
                                .allowIfSubType(Object.class)
                                .build(),
                        DefaultTyping.NON_FINAL,
                        JsonTypeInfo.As.PROPERTY
                )
                .changeDefaultVisibility(visibilityChecker -> VisibilityChecker.defaultInstance()
                        // .withFieldVisibility(Visibility.ANY)
                        // .withGetterVisibility(Visibility.ANY)
                        // .withIsGetterVisibility(Visibility.ANY)
                        // .withSetterVisibility(Visibility.ANY)
                        // .withCreatorVisibility(Visibility.ANY)
                        .with(JsonAutoDetect.Visibility.ANY)
                )
                .build();
        JacksonJsonRedisSerializer<Object> jacksonJsonRedisSerializer = new JacksonJsonRedisSerializer<>(jsonMapper, Object.class);

        // 针对每一个消息处理可以设置不同的序列化方式
        // 收藏主题并绑定消息订阅处理器
        collectListenerAdapter.setSerializer(jacksonJsonRedisSerializer);
        container.addMessageListener(collectListenerAdapter, new PatternTopic(RedisConstant.TOPIC_COLLECT));
        // 评论主题并绑定消息订阅处理器
        commentListenerAdapter.setSerializer(jacksonJsonRedisSerializer);
        container.addMessageListener(commentListenerAdapter, new PatternTopic(RedisConstant.TOPIC_COMMENT));
        // 关注主题并绑定消息订阅处理器
        focusListenerAdapter.setSerializer(jacksonJsonRedisSerializer);
        container.addMessageListener(focusListenerAdapter, new PatternTopic(RedisConstant.TOPIC_FOCUS));
        // 点赞主题并绑定消息订阅处理器
        praiseListenerAdapter.setSerializer(jacksonJsonRedisSerializer);
        container.addMessageListener(praiseListenerAdapter, new PatternTopic(RedisConstant.TOPIC_PRAISE));
        //
        webSocketTopicListenerAdapter.setSerializer(jacksonJsonRedisSerializer);
        container.addMessageListener(webSocketTopicListenerAdapter, new PatternTopic("webSocketTopic"));
        return container;
    }

    /**
     * 收藏消息订阅处理器，并指定处理方法
     *
     * @param redisReceiver
     * @return
     */
    @Bean
    MessageListenerAdapter collectListenerAdapter(RedisReceiver redisReceiver) {
        MessageListenerAdapter messageListenerAdapter = new MessageListenerAdapter(redisReceiver, "receiveCollect");
        return messageListenerAdapter;
    }

    /**
     * 评论消息订阅处理器，并指定处理方法
     *
     * @param redisReceiver
     * @return
     */
    @Bean
    MessageListenerAdapter commentListenerAdapter(RedisReceiver redisReceiver) {
        MessageListenerAdapter messageListenerAdapter = new MessageListenerAdapter(redisReceiver, "receiveComment");
        return messageListenerAdapter;
    }

    /**
     * 关注消息订阅处理器，并指定处理方法
     *
     * @param redisReceiver
     * @return
     */
    @Bean
    MessageListenerAdapter focusListenerAdapter(RedisReceiver redisReceiver) {
        MessageListenerAdapter messageListenerAdapter = new MessageListenerAdapter(redisReceiver, "receiveFocus");
        return messageListenerAdapter;
    }

    /**
     * 点赞消息订阅处理器，并指定处理方法
     *
     * @param redisReceiver
     * @return
     */
    @Bean
    MessageListenerAdapter praiseListenerAdapter(RedisReceiver redisReceiver) {
        MessageListenerAdapter messageListenerAdapter = new MessageListenerAdapter(redisReceiver, "receivePraise");
        return messageListenerAdapter;
    }

    @Bean
    MessageListenerAdapter webSocketTopicListenerAdapter(RedisReceiver redisReceiver) {
        MessageListenerAdapter messageListenerAdapter = new MessageListenerAdapter(redisReceiver, "webSocketTopicReceive");
        return messageListenerAdapter;
    }
}
